﻿using System;
using System.Drawing;
using System.IO;
using System.Net;
using System.Text;
using System.Windows.Forms;
using ESBasic;
using Oraycn.MCapture;
using Oraycn.MFile;

namespace Oraycn.RecordDemo
{
  /*
  * 本demo采用的是 语音视频采集组件MCapture 和 语音视频录制组件MFile 的免费版本。若想获取MCapture、MFile的其它版本，请联系 www.oraycn.com ,客服qq：168757008。
  *
  */

  public partial class Form1 : Form
  {
    private string _file;
    private string _postUrl;
    private ISoundcardCapturer _soundcardCapturer;
    private IMicrophoneCapturer _microphoneCapturer;
    private IDesktopCapturer _desktopCapturer;
    private ICameraCapturer _cameraCapturer;
    private IAudioMixter _audioMixter;
    private VideoFileMaker _videoFileMaker;
    private SilenceVideoFileMaker _silenceVideoFileMaker;
    private AudioFileMaker _audioFileMaker;
    private const int FrameRate = 10; // 采集视频的帧频
    private bool _sizeRevised = false; // 是否需要将图像帧的长宽裁剪为4的整数倍
    private bool _isRecording = false;
    private bool _isParsing = false;
    private readonly Timer _timer;
    private int _seconds = 0;
    private bool _justRecordVideo = false;
    private bool _justRecordAudio = false;

    public Form1(string file, string postUrl)
    {
      InitializeComponent();
      Oraycn.MCapture.GlobalUtil.SetAuthorizedUser("FreeUser", "");
      Oraycn.MFile.GlobalUtil.SetAuthorizedUser("FreeUser", "");

      this._timer = new Timer {Interval = 1000};
      this._timer.Tick += new EventHandler(timer_Tick);
      this._file = file;
      this._postUrl = postUrl;
    }

    private static int _i = 0;

    private void timer_Tick(object sender, EventArgs e)
    {
      if (!this._isRecording || this._isParsing) return;
      var ts = new TimeSpan(0, 0, ++_seconds);
      this.label_time.Text = ts.Hours.ToString("00") + @":" + ts.Minutes.ToString("00") + @":" +
                             ts.Seconds.ToString("00");

      if (_i < 9)
      {
        _i++;
        return;
      }

      this.button_stop_Click(sender, e);

      PostImage(this._file, this._postUrl);

      this.button_start_Click(sender, e);

      _i = 0;
    }

    private static void PostImage(string path, string url)
    {
      try
      {
        // 设置参数
        HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
        CookieContainer cookieContainer = new CookieContainer();
        request.CookieContainer = cookieContainer;
        request.AllowAutoRedirect = true;
        request.Method = "POST";
        string boundary = DateTime.Now.Ticks.ToString("X"); // 随机分隔线
        request.ContentType = "multipart/form-data;charset=utf-8;boundary=" + boundary;
        byte[] itemBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");
        byte[] endBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");

        int pos = path.LastIndexOf("\\");
        string fileName = path.Substring(pos + 1);

        //请求头部信息
        StringBuilder sbHeader =
          new StringBuilder(
            string.Format(
              "Content-Disposition:form-data;name=\"file\";filename=\"{0}\"\r\nContent-Type:application/octet-stream\r\n\r\n",
              fileName));
        byte[] postHeaderBytes = Encoding.UTF8.GetBytes(sbHeader.ToString());

        FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
        byte[] bArr = new byte[fs.Length];
        fs.Read(bArr, 0, bArr.Length);
        fs.Close();

        Stream postStream = request.GetRequestStream();
        postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);
        postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
        postStream.Write(bArr, 0, bArr.Length);
        postStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
        postStream.Close();

        //发送请求并获取相应回应数据
        HttpWebResponse response = request.GetResponse() as HttpWebResponse;
        //直到request.GetResponse()程序才开始向目标网页发送Post请求
        Stream instream = response.GetResponseStream();
        StreamReader sr = new StreamReader(instream, Encoding.UTF8);
        //返回结果网页（html）代码
        string content = sr.ReadToEnd();
      }
      catch (Exception e)
      {
        MessageBox.Show(e.Message);
      }
    }

    #region 开始录制

    private void button_start_Click(object sender, EventArgs e)
    {
      // 开始录制桌面，依据 声音复选框 来选择使用 声卡 麦克风 还是混合录制, 图像复选框来选择 图像的采集器
      try
      {
        var audioSampleRate = 16000;
        var channelCount = 1;
        _seconds = 0;

        var videoSize = Screen.PrimaryScreen.Bounds.Size;
        this._justRecordAudio = this.radioButton_justAudio.Checked;

        if (this._justRecordAudio && !this.checkBox_micro.Checked && !this.checkBox_soundCard.Checked)
        {
          MessageBox.Show(@"一定要选择一个声音的采集源！");
          return;
        }

        #region 设置采集器

        if (this.radioButton_desktop.Checked)
        {
          //桌面采集器

          //如果需要录制鼠标的操作，第二个参数请设置为true
          this._desktopCapturer = CapturerFactory.CreateDesktopCapturer(FrameRate, false);
          this._desktopCapturer.ImageCaptured += this.Form1_ImageCaptured;
          videoSize = this._desktopCapturer.VideoSize;
        }
        else if (this.radioButton_camera.Checked)
        {
          //摄像头采集器
          videoSize = new System.Drawing.Size(int.Parse(this.textBox_width.Text), int.Parse(this.textBox_height.Text));
          this._cameraCapturer = CapturerFactory.CreateCameraCapturer(0, videoSize, FrameRate);
          this._cameraCapturer.ImageCaptured += new CbGeneric<Bitmap>(this.Form1_ImageCaptured);
        }

        if (this.checkBox_micro.Checked)
        {
          //麦克风采集器
          this._microphoneCapturer = CapturerFactory.CreateMicrophoneCapturer(0);
          this._microphoneCapturer.CaptureError += new CbGeneric<Exception>(this.CaptureError);
        }

        if (this.checkBox_soundCard.Checked)
        {
          //声卡采集器 【目前声卡采集仅支持vista以及以上系统】
          this._soundcardCapturer = CapturerFactory.CreateSoundcardCapturer();
          this._soundcardCapturer.CaptureError += this.CaptureError;
          audioSampleRate = this._soundcardCapturer.SampleRate;
          channelCount = this._soundcardCapturer.ChannelCount;
        }

        if (this.checkBox_micro.Checked && this.checkBox_soundCard.Checked)
        {
          //混音器
          this._audioMixter = CapturerFactory.CreateAudioMixter(this._microphoneCapturer, this._soundcardCapturer,
            SoundcardMode4Mix.DoubleChannel, true);
          this._audioMixter.AudioMixed += audioMixter_AudioMixed;
          audioSampleRate = this._audioMixter.SampleRate;
          channelCount = this._audioMixter.ChannelCount;
        }
        else if (this.checkBox_micro.Checked)
        {
          this._microphoneCapturer.AudioCaptured += audioMixter_AudioMixed;
        }
        else if (this.checkBox_soundCard.Checked)
        {
          this._soundcardCapturer.AudioCaptured += audioMixter_AudioMixed;
        }

        #endregion

        #region //开始采集

        if (this.checkBox_micro.Checked)
        {
          this._microphoneCapturer.Start();
        }
        if (this.checkBox_soundCard.Checked)
        {
          this._soundcardCapturer.Start();
        }

        if (this.radioButton_camera.Checked)
        {
          this._cameraCapturer.Start();
        }
        else if (this.radioButton_desktop.Checked)
        {
          this._desktopCapturer.Start();
        }

        #endregion

        #region //录制组件

        if (this._justRecordAudio)
        {
          //只录制声音
          this._audioFileMaker = new AudioFileMaker();
          this._audioFileMaker.Initialize(this._file, audioSampleRate, channelCount);
        }
        else
        {
          this._sizeRevised = (videoSize.Width % 4 != 0) || (videoSize.Height % 4 != 0);
          if (this._sizeRevised)
          {
            videoSize = new System.Drawing.Size(videoSize.Width / 4 * 4, videoSize.Height / 4 * 4);
          }

          if (!this.checkBox_micro.Checked && !this.checkBox_soundCard.Checked)
          {
            //只录制 图像
            this._justRecordVideo = true;
            this._silenceVideoFileMaker = new SilenceVideoFileMaker();
            this._silenceVideoFileMaker.Initialize(this._file, VideoCodecType.H264, videoSize.Width,
              videoSize.Height,
              FrameRate, VideoQuality.High);
          }
          else
          {
            // 录制声音和图像
            this._justRecordVideo = false;
            this._videoFileMaker = new VideoFileMaker();
            this._videoFileMaker.Initialize(this._file, VideoCodecType.H264, videoSize.Width, videoSize.Height,
              FrameRate, VideoQuality.High, AudioCodecType.AAC, audioSampleRate, channelCount, true);
          }
        }

        #endregion

        this._isRecording = true;
        this._isParsing = false;

        this._timer.Start();

        this.checkBox_micro.Enabled = false;
        this.checkBox_soundCard.Enabled = false;
        this.radioButton_desktop.Enabled = false;
        this.radioButton_camera.Enabled = false;
        this.radioButton_justAudio.Enabled = false;

        this.button_start.Enabled = false;
      }
      catch (Exception ee)
      {
        MessageBox.Show(ee.Message);
      }
    }

    #region CaptureError

    public void CaptureError(Exception obj)
    {
    }

    #endregion

    #region Form1_ImageCaptured

    //采集到的视频或桌面图像
    public void Form1_ImageCaptured(Bitmap img)
    {
      if (!this._isRecording || this._isParsing) return;
      //这里要裁剪
      var imgRecorded = img;
      if (this._sizeRevised) // 对图像进行裁剪，  MFile要求录制的视频帧的长和宽必须是4的整数倍。
      {
        imgRecorded = ESBasic.Helpers.ImageHelper.RoundSizeByNumber(img, 4);
        img.Dispose();
      }
      if (!this._justRecordVideo)
      {
        this._videoFileMaker.AddVideoFrame(imgRecorded);
      }
      else
      {
        this._silenceVideoFileMaker.AddVideoFrame(imgRecorded);
      }
    }

    #endregion

    #region audioMixter_AudioMixed

    public void audioMixter_AudioMixed(byte[] audioData)
    {
      if (!this._isRecording || this._isParsing) return;
      if (this._justRecordAudio)
      {
        this._audioFileMaker.AddAudioFrame(audioData);
      }
      else
      {
        if (!this._justRecordVideo)
        {
          this._videoFileMaker.AddAudioFrame(audioData);
        }
      }
    }

    #endregion

    #endregion

    #region 暂停

    private void button_parse_Click(object sender, EventArgs e)
    {
      // 暂停当前录制或恢复录制
      // label 中显示实际录制的时间，需要考虑暂停和恢复这种情况。 格式为 hh:mm:ss
      this._isParsing = !this._isParsing;
      this.button_parse.Text = (!this._isParsing ? "暂停" : "恢复");
    }

    #endregion

    #region 结束录制

    private void button_stop_Click(object sender, EventArgs e)
    {
      this.checkBox_micro.Enabled = true;
      this.checkBox_soundCard.Enabled = true;
      this.radioButton_camera.Enabled = true;
      this.radioButton_desktop.Enabled = true;
      this.radioButton_justAudio.Enabled = true;

      this.button_start.Enabled = true;
      this.button_parse.Text = @"暂停";

      if (this.checkBox_micro.Checked) // 麦克风
      {
        this._microphoneCapturer.Stop();
      }
      if (this.checkBox_soundCard.Checked) //声卡
      {
        this._soundcardCapturer.Stop();
      }
      if (this.radioButton_camera.Checked)
      {
        this._cameraCapturer.Stop();
      }
      if (this.radioButton_desktop.Checked)
      {
        this._desktopCapturer.Stop();
      }
      if (this._justRecordAudio)
      {
        this._audioFileMaker.Close(true);
      }
      else
      {
        if (!this._justRecordVideo)
        {
          this._videoFileMaker.Close(true);
        }
        else
        {
          this._silenceVideoFileMaker.Close(true);
        }
      }

      this._isRecording = false;
    }

    #endregion

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
      if (this._isRecording)
      {
        MessageBox.Show(@"正在录制中，退出前请先停止录制！");
        e.Cancel = true;
        return;
      }

      e.Cancel = false;
    }

    private void radioButton_camera_CheckedChanged(object sender, EventArgs e)
    {
      this.panel_camera.Visible = true;
    }

    private void radioButton_desktop_CheckedChanged(object sender, EventArgs e)
    {
      this.panel_camera.Visible = false;
    }

    private void radioButton_justAudio_CheckedChanged(object sender, EventArgs e)
    {
      this.panel_camera.Visible = false;
    }
  }
}